/*
 * (c) 2007, Delsi Interactive
 * User: Usuario Deltatek
 * Date: 02/05/2007
 * Time: 08:23 p.m.
 */

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;

namespace CSE
{
	/// <summary>
	/// Description of GetClips.
	/// </summary>
	public partial class GetClips : Form
	{
		/*
		 * Constants
		 */
		public static readonly string CLIP_NAME = "clip_";
		public static readonly string WINDOW_NAME = "Working...";
		public static readonly int MAX_PROGRESS = 15;
		
		/*
		 * Variables
		 */
		private Stack<Point> known_points   = null;
		private Stack<Point> next_points    = null;
		
		private Rectangle r;
		
#if _DEBUG_GETCLIPS
		private int ox = 0;
		private int oy = 0;
#endif
		
		private bool done = false;
		private bool cancel = false;
		
		/*
		 * Constructor
		 */
		public GetClips()
		{
			MainForm.self.Enabled = false;
			r = new Rectangle(0,0,0,0);
			
			next_points = new Stack<Point>();
			known_points = new Stack<Point>();
			
			InitializeComponent();
			
			this.Location = new Point (MainForm.self.Location.X + (MainForm.self.Width / 2) - (this.Width / 2),
			                           MainForm.self.Location.Y + (MainForm.self.Height / 2) - (this.Height / 2));
			this.btnOk.Visible = false;
			this.btnCancel.Visible = true;
			this.prgBar.Value = 0;
			
			this.Text = WINDOW_NAME;

			this.Show(MainForm.self);
			this.Focus();
			
			ProcessBitmap();
		}
		
		/*
		 * For debug only
		 */
		void PicPaint(object sender, PaintEventArgs e)
		{
#if _DEBUG_GETCLIPS
		    Graphics g = e.Graphics;
		    
		    g.Clear(Color.Black);
		    g.DrawImage(Workspace.bitmap, 0, 0);
		    
		    Pen p = new Pen(Color.Turquoise);
		    g.DrawRectangle(p, ox-1, oy-1, 3, 3);
#endif
		}
		
        /*
		 * UnloadMe
		 */
		private void UnloadMe ()
		{
			MainForm.self.Enabled = true;
			this.Dispose();
			MainForm.gc = null;
		}
		
		/*
		 * ProcessBitmap:
		 * Generates all the clips.
		 */
		private void ProcessBitmap ()
		{
			Bitmap bitmap = Workspace.bitmap;
			int x=0, y=0;
        	int width = bitmap.Width;
        	int height = bitmap.Height;
        	int percent = 0;
        	int clip_num = 0;
        	Color trans = bitmap.GetPixel(0, 0);
        	
            /*
        	 * Crosses the image pixel by pixel
        	 */
        	for (y=0; y<height; y++)
        	{
        		for (x=0; x<width; x++)
        		{
        		    /*
        		     * If this pixel isn't transparent
        		     * and if it's a valid point,
        		     * process him!
        		     */
        			if (bitmap.GetPixel(x, y) != trans
        		    && IsValidPoint(x, y, false))
        			{
#if _DEBUG_GETCLIPS
        		        ox = x;
        				oy = y;
#endif
						Point p = new Point(x, y);
        				r.X = x;
        				r.Y = y;
        				r.Width = 0;
        				r.Height = 0;
        				done = false;
        				
        				while (!done)
        				{
        				    /*
        				     * ProcessRect analyzes the point in which we are.
        				     * In case of being able to go towards another point,
        				     * this function will push the new Point to the stack.
        				     */
        				    r = ProcessRect(x, y, r, bitmap, trans);
        				    
        				    while (next_points.Count > 0)
        				    {
        				        if (cancel)
        				        {
        				            done = true;
        				            x = width;
        				            y = height;
        				            break;
        				        }
        				        else
        				        {
        				        	/*
	                    		     * Adjust our clip box based on the new coordinates
	                    		     */
	                    		    while (p.X < r.X)
	                                {
	                                    r.X--;
	                                    r.Width++;
	                                }
	                    			while (p.X >= r.X + r.Width)
	                                {
	                                    r.Width++;
	                                }
	                    			while (p.Y < r.Y)
	                                {
	                                    r.Y--;
	                                    r.Height++;
	                                }
	                    			while (p.Y >= r.Y + r.Height)
	                    			{
	                    				r.Height++;
	                    			}
        				        }
        				        
        				        p = next_points.Pop();
#if _DEBUG_GETCLIPS
        				        ox = p.X;
        				        oy = p.Y;
#endif
        				        
        				        r = ProcessRect(p.X, p.Y, r, bitmap, trans);
        				        
        				        /*
        				         * And we let breathe the application.
        				         */
#if _DEBUG_GETCLIPS
        				        this.picTemp.Invalidate();
#endif
			                    Application.DoEvents();
        				    }
        				}
        				
        				/*
        				 * If the resulting rectangle is valid to be added...
        				 */
        				if (r.Width > 3 && r.Height > 3)
        				{
#if _DEBUG_GETCLIPS
        				    Utils.Trace(">> rect: " + r.ToString());
#endif
        				    
        				    /*
        				     * Push him to the library.
        				     */
            				MainForm.libSel = MainForm.libClipsLibrary;
        				    TreeNode nt = Workspace.NewClip(Workspace.TYPE_CLIP, (CLIP_NAME + clip_num).ToString(), true);
        				    ((Clip)nt.Tag).r.X = r.X;
        				    ((Clip)nt.Tag).r.Y = r.Y;
        				    ((Clip)nt.Tag).r.Width = r.Width;
        				    ((Clip)nt.Tag).r.Height = r.Height;
        				    clip_num++;
        				}
        			}
        			
        		    /*
        		     * TODO: make the next shit look better...
        		     */
        		    percent = Convert.ToInt32(Math.Floor((double)(((x * y) * 100) / (double)(width * height))));
        			if (percent != 0
        			&& percent > this.prgBar.Value)
        			{
        				this.prgBar.Value = percent;
        			}
        			Application.DoEvents();
        		}
        	}
        	
        	known_points = null;
        	next_points = null;
        	
        	this.btnOk.Visible = true;
        	this.btnCancel.Visible = false;
		}
		
		/*
		 * IsValidPoint
		 */
		private bool IsValidPoint (int x, int y, bool addifnotpresent)
		{
			foreach (Point p in known_points)
			{
				if (p.X == x
				&& p.Y == y)
				{
					return false;
				}
			}
			
			if (!addifnotpresent)
			{
				return true;
			}
			
			known_points.Push(new Point(x, y));
			return true;
		}
		
		/*
		 * ProcessRect:
		 * FloodFill like algorithm but:
		 * 1) non-recursive
		 * 2) more like the QuickFill algorithm.
		 */
		private Rectangle ProcessRect (int x, int y, Rectangle r, Bitmap bitmap, Color trans)
		{
		    /*
			 * If it's not a valid point...
			 * Find another way!
			 */
			if (!IsValidPoint(x, y, true))
			{
				int old_x = x;
				int old_y = y;
				int start = old_x - 1;
				bool anyvalid = false;
				
				while (start >= 0)
				{
					if (bitmap.GetPixel(start, old_y) == trans)
					{
						break;
					}
					
				    if (IsValidPoint(start, old_y, false))
				    {
				        x = start;
				        next_points.Push(new Point(start, old_y));
				        anyvalid = true;
				        break;
				    }
				    start--;
				}
				
				start = old_x + 1;
				while (start <= bitmap.Width - 1)
				{
					if (bitmap.GetPixel(start, old_y) == trans)
					{
						break;
					}
					
				    if (IsValidPoint(start, old_y, false))
				    {
				        x = start;
				        next_points.Push(new Point(start, old_y));
				        anyvalid = true;
				        break;
				    }
				    start++;
				}
				
				start = old_y - 1;
				while (start >= 0)
				{
					if (bitmap.GetPixel(old_x, start) == trans)
					{
						break;
					}
						
				    if (IsValidPoint(old_x, start, false))
				    {
				        y = start;
				        next_points.Push(new Point(old_x, start));
				        anyvalid = true;
				        break;
				    }
				    start--;
				}
				
				start = old_y + 1;
				while (start < bitmap.Height - 1)
				{
					if (bitmap.GetPixel(old_x, start) == trans)
					{
						break;
					}
					
				    if (IsValidPoint(old_x, start, false))
				    {
				        y = start;
				        next_points.Push(new Point(old_x, start));
				        anyvalid = true;
				        break;
				    }
				    start++;
				}
				
				if (!anyvalid)
				{
				    done = true;
				}
                
				return r;
			}
			
			// Move LEFT
			if (x > 0)
			{
				if (bitmap.GetPixel(x - 1, y) != trans)
				{
				    if (IsValidPoint(x - 1, y, false))
			    	{
					    x--;
				    	next_points.Push(new Point(x, y));
			    	}
				}
			}
			
			// Move RIGHT
			if (x < bitmap.Width - 1)
			{
				if (bitmap.GetPixel(x + 1, y) != trans)
				{
					if (IsValidPoint(x + 1, y, false))
			    	{
					    x++;
    					next_points.Push(new Point(x, y));
					}
				}
			}
			
			// Move TOP
			if (y > 0)
			{
				if (bitmap.GetPixel(x, y - 1) != trans)
				{
					if (IsValidPoint(x, y - 1, false))
			    	{
					    y--;
    					next_points.Push(new Point(x, y));
					}
				}
			}
			
			// Move BOTTOM
			if (y < bitmap.Height - 1)
			{
				if (bitmap.GetPixel(x, y + 1) != trans)
				{
					if (IsValidPoint(x, y + 1, false))
			    	{
					    y++;
    					next_points.Push(new Point(x, y));
					}
				}
			}
			
			return r;
		}
		
		/*
		 * Ok
		 */
		void BtnOkClick(object sender, EventArgs e)
		{
			UnloadMe();
		}
		
		/*
		 * Cancel
		 */
		void BtnCancelClick(object sender, EventArgs e)
		{
			cancel = true;
		}
	}
}
